package top.linuyx.service.impl;

import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import top.linuyx.exception.GlobalException;
import top.linuyx.mapper.UserMapper;
import top.linuyx.pojo.entity.AccountEntity;
import top.linuyx.pojo.param.UserBindEmailParam;
import top.linuyx.pojo.param.UserUpdateParam;
import top.linuyx.pojo.param.UserUpdatePasswordParam;
import top.linuyx.service.UserService;
import top.linuyx.service.VerificationCodeService;
import top.linuyx.utils.MallUtils;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

/**
 * @Author Linuyx
 * @Description UserService实现类 处理:修改用户信息、绑定邮箱、修改密码、上传用户图片等业务
 * @Date Created in 2021-04-16 15:10
 */

@Service
public class UserServiceImpl implements UserService {

    /**
     * 图片上传路径
     */
    @Value("${file.image.uploadPath}")
    private String imageUploadPath;

    /**
     * 图片访问路径
     */
    @Value("${file.image.accessPath}")
    private String imageAccessPath;

    /**
     * 绑定邮箱RedisKey格式
     */
    @Value("${verification-code.bind-mail}")
    private String bindMailKey;

    /**
     * 修改密码RedisKey格式
     */
    @Value("${verification-code.update-password}")
    private String updatePasswordKey;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 修改用户信息
     *
     * @param updateParam 用户信息
     */
    @Override
    public void updateUser(UserUpdateParam updateParam) {
        //获得当前登录的用户
        String username = MallUtils.getUser();

        //性别用数字表示, 1 男, 0 女
        updateParam.setSexId(MallUtils.getSexId(updateParam.getSexName()));

        //通过用户名查询用户id
        Long userId = userMapper.getIdByUsername(username);
        updateParam.setUserId(userId);

        userMapper.updateUserById(updateParam);
    }

    /**
     * 绑定邮箱
     *
     * @param bindEmailParam 绑定邮箱请求体
     */
    @Override
    public void bindEmail(UserBindEmailParam bindEmailParam) {
        //获得当前登录的用户
        String username = MallUtils.getUser();

        //判断验证码是否过期
        Long expireTime = redisTemplate.getExpire(bindMailKey + username);
        if (expireTime == -2) {
            throw new GlobalException("验证码已失效");
        }

        //如果验证码未过期,获取验证码
        //判断绑定的邮箱和发送验证码的邮箱是否一致
        String emailAndVerificationCode = (String) redisTemplate.opsForValue().get(bindMailKey + username);
        if (!emailAndVerificationCode.substring(0, emailAndVerificationCode.indexOf(":")).equals(bindEmailParam.getEmail())) {
            throw new GlobalException("绑定的邮箱必须与发送验证码的邮箱一致");
        }

        //判断验证码是否正确
        String verificationCode = emailAndVerificationCode.substring(emailAndVerificationCode.indexOf(":") + 1);
        if (!verificationCode.equals(bindEmailParam.getVerificationCode().toLowerCase())) {
            throw new GlobalException("验证码不正确");
        }

        synchronized (this) {
            //判断邮箱是否已经被绑定
            if (userMapper.getEmail(bindEmailParam.getEmail()) != null) {
                throw new GlobalException("邮箱已被绑定");
            }

            //根据用户名查询用户id
            Long userId = userMapper.getIdByUsername(username);
            bindEmailParam.setUserId(userId);

            //绑定邮箱
            userMapper.bindEmail(bindEmailParam);
        }

        //绑定成功后删除验证码,单次验证有效
        redisTemplate.delete(bindMailKey + username);
    }

    /**
     * 修改密码
     *
     * @param updatePasswordParam 修改密码请求体
     */
    @Override
    public void updatePassword(UserUpdatePasswordParam updatePasswordParam) {
        //判断新密码与旧密码是否重复
        if (updatePasswordParam.getNewPassword().equals(updatePasswordParam.getOldPassword())) {
            throw new GlobalException("新密码不能与旧密码重复");
        }

        //获得当前登录的用户
        String username = MallUtils.getUser();

        //判断验证码是否过期
        Long expireTime = redisTemplate.getExpire(updatePasswordKey + username);
        if (expireTime == -2) {
            throw new GlobalException("验证码已失效");
        }

        //如果验证码未过期,获取验证码,并判断验证码是否正确
        String verificationCode = (String) redisTemplate.opsForValue().get(updatePasswordKey + username);
        if (!verificationCode.equals(updatePasswordParam.getVerificationCode().toLowerCase())) {
            throw new GlobalException("验证码不正确");
        }

        //根据用户名查询密码
        AccountEntity account = userMapper.getAccountByUsername(username);
        //对用户输入的旧密码进行 md5加密 + salt + hash散列(1024)
        Md5Hash md5Hash = new Md5Hash(updatePasswordParam.getOldPassword(), account.getSalt(), 1024);
        String oldPassword = md5Hash.toHex();
        //判断旧密码是否正确
        if (!oldPassword.equals(account.getPassword())) {
            throw new GlobalException("旧密码不正确");
        }

        //对新密码进行 md5加密 + salt + hash散列(1024)
        md5Hash = new Md5Hash(updatePasswordParam.getNewPassword(), account.getSalt(), 1024);
        String newPassword = md5Hash.toHex();
        //根据用户名修改密码
        userMapper.updatePasswordByUsername(username, newPassword);

        //密码修改成功后删除验证码,单次验证有效
        redisTemplate.delete(updatePasswordKey + username);
    }

    /**
     * 上传用户图片
     *
     * @param multipartFile 图片
     */
    @Override
    public void uploadImage(MultipartFile multipartFile) {
        //获得当前登录的用户
        String username = MallUtils.getUser();

        //获取图片后缀名
        String suffixName = multipartFile.getOriginalFilename()
                .substring(multipartFile.getOriginalFilename().lastIndexOf("."));

        //判断图片格式是否符合规定
        if (!suffixName.equals(".jpg") && !suffixName.equals(".jpeg") && !suffixName.equals(".png")) {
            throw new GlobalException("图片格式不符合规定格式:.jpg .jpeg .png");
        }

        //生成图片名
        String imageName = UUID.randomUUID().toString().replace("-", "");
        //服务器路径+文件名+后缀名
        String uploadPath = imageUploadPath + imageName + suffixName;

        //上传图片
        try {
            multipartFile.transferTo(new File(uploadPath));
        } catch (IOException e) {
            throw new GlobalException("图片上传失败");
        }

        //根据用户名查询id
        Long userId = userMapper.getIdByUsername(username);

        //删除原来的图片
        String oldImage = userMapper.getImageById(userId);
        if (oldImage != null) {
            //将访问路径修改为上传时服务器上的路径
            String severImageName = imageUploadPath + oldImage.replace(imageAccessPath, "");
            new File(severImageName).delete();
        }

        //将新图片修改到数据库
        String newImage = imageAccessPath + imageName + suffixName;
        userMapper.updateImageById(userId, newImage);
    }

}
